/*
 * SafeNumberList.cpp
 *
 *  Created on:  Jun 12, 2009
 *      Author:  Zach Riggle A37627537
 *      Project: CSE410 Project 2
 */

#include <unistd.h>
#include <sys/errno.h>
#include "Log.h"
#include "SafeNumberList.h"

SafeNumberList::SafeNumberList() {
    sorted.set(0);
}

SafeNumberList::~SafeNumberList() {

}

void SafeNumberList::lock(int first, int second) {
    int lock1 = -1;
    int lock2 = -1;

    int nSeconds = 100;

    info("Attempting to lock " << first << " and " << second);

    // As long as we can't get BOTH locks, keep freeing up whichever one we do get,
    // sleep for a bit, then try again.
    while ( lock1 != 0 || lock2 != 0) {
        lock1 = get(first)->tryLock();
        lock2 = get(second)->tryLock();
        // Did we get a lock??
        if (lock1 == 0 && lock2 == 0) {
            break;
        } else if (lock1 == 0) {
            debug("Unlocking " << first << " while waiting for " << second);
            get(first)->unlock();
        } else if (lock2 == 0) {
            debug("Unlocking " << second << " while waiting for " << first);
            get(second)->unlock();
        } else {
            debug("Didn't get either lock.");

            if ( lock1 == EINVAL )
                debug("Not initialized.");
            else if (lock1 == EBUSY)
                debug("Already locked.");
            else if (lock1 == EFAULT)
                debug("Invalid pointer.");
            else
                debug("Unknown error.");
        }

        // sleep 10 microseconds
        usleep(nSeconds);
        nSeconds *= 2;
    }

    debug("Got lock for " << first << " and " << second);

    // Great, we have both locks.
}

void SafeNumberList::unlock(int first, int second) {
    debug("Unlocking " << first << " and " << second);
    // Unlock both of them
    get(first)->unlock();
    get(second)->unlock();
}

LockedNumber* SafeNumberList::get(int offset) {
    if (offset < size())
        return numberList[offset];
    return NULL;
}

LockedNumber* SafeNumberList::operator [](int offset) {
    return get(offset);
}

int SafeNumberList::size() {
    return numberList.size();
}

void SafeNumberList::setList(vector<int> v) {
    // Free up anything in the list...
    for (int i = 0; i < size(); i++) {
        debug("Deleting " << numberList[i]->get() << " from the list");
        delete numberList[i];
    }

    // Add all of the new numbers...
    for (int i = 0; i < v.size(); i++) {
        LockedNumber *ln = new LockedNumber();
        ln->set(v[i]);
        numberList.push_back(ln);

        debug("Added " << ln->get() << " from the list");
    }
}

vector<int> SafeNumberList::getList() {
    vector<int> v;

    for (int i = 0; i < size(); i++) {
        v.push_back(numberList[i]->get());
    }

    return v;
}
